//========================================================================
/**
 * Author   : cuisw <shaovie@gmail.com>
 * Date     : 2008-10-24 18:36
 */
//========================================================================

#ifndef _EPOLLASYNCHIO_H_
#define _EPOLLASYNCHIO_H_
#include "Pre.h"

#include "AsynchIO.h"
#include "AsynchIOImpl.h"

class EpollProactor;

/**
 * @class EpollAsynchOpt
 *
 * @brief Asynchronous I/O for epoll actually is non-blocking I/O.  
 */
class EpollAsynchResult;
class EpollAsynchOpt : public virtual AsynchOptImpl
{
    friend class EpollProactor;

    friend class EpollProactorWriteTask;
public:
    /**
     * Initializes the factory with information which will be used with
     * each asynchronous call.  If (handle == NDK_INVALID_HANDLE),
     * @c AsynchHandler::handle will be called on the handler to get the
     * correct handle. No need for the Proactor since the sub classes
     * will know the correct implementation Proactor class, since this
     * Operation class itself was created by the correct implementation
     * Proactor class.
     */
    virtual int open (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    const void *completion_key,
	    Proactor *proactor = 0);

    // Check the documentation for AsynchOpt::cancel.
    //virtual int cancel (void);

    // Return the underlying proactor.
    Proactor* proactor (void) const;

    // Return the underlying Proactor implementation.
    EpollProactor *proactor_impl (void) const;

    EpollAsynchResult *result (void) const;

    void result (EpollAsynchResult *);

    NDK_HANDLE handle (void) const;
protected:
    EpollAsynchOpt (EpollProactor *);

    virtual ~EpollAsynchOpt();

    // I/O operation and build result.
    virtual int execute (EpollAsynchResult *&) = 0;

    /**
     * It is easy to get this specific implementation proactor here,
     * since it is the one that creates the correct EpollAsynch_*
     * objects. We can use this to get to the implementation proactor
     * directly.
     */
    EpollProactor *epoll_proactor_;

    Proactor *proactor_;
    
    // Handler that will receive the callback.
    AsynchHandler *asynch_handler_;

    // I/O handle .
    NDK_HANDLE handle_;

    EpollAsynchResult *result_;
};
// ---------------------------------------------------------------------
/**
 * @class EpollAsynchResult
 *
 * @brief 
 */
class EpollAsynchResult : public virtual AsynchResultImpl
{
    friend class EpollProactor;

    friend class EpollProactorWriteTask;
public:
    virtual ~EpollAsynchResult ();

    // Number of bytes transferred by the operation.
    virtual size_t bytes_transferred (void) const;

    // Did the operation succeed?
    virtual int success (void) const;

    virtual const void *completion_key (void) const;

    // Error value if the operation fail.
    virtual int error (void) const;

    virtual NDK_HANDLE get_handle (void) const;

    //
    virtual long long offset (void) const;
protected:
    EpollAsynchResult (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    long long offset);

    //
    NDK_HANDLE handle_;

    // Bytes transferred by this operation.
    size_t bytes_transferred_;

    // Success indicator.
    int success_;

    //
    const void *completion_key_;

    AsynchHandler *asynch_handler_;

    // Error of operation failed.
    int error_;

    long long offset_;
};
// ---------------------------------------------------------------------
/**
 * @class EpollAsynchReadStream
 *
 * @brief .
 */
class EpollAsynchReadStreamResult;
class EpollAsynchReadStream : 
    public virtual AsynchReadStreamImpl, 
    public EpollAsynchOpt
{
    // The Proactor constructs the Result class for faking results.
    friend class EpollProactor;
public:
    // Constructor.
    EpollAsynchReadStream (EpollProactor *p);

    /**
     * Initializes the factory with information which will be used with
     * each asynchronous call.  If (handle == NDK_INVALID_HANDLE),
     * @c AsynchHandler::handle will be called on the handler to get the
     * correct handle. No need for the Proactor since the sub classes
     * will know the correct implementation Proactor class, since this
     * Operation class itself was created by the correct implementation
     * Proactor class.
     */
    virtual int open (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    const void *completion_key,
	    Proactor *proactor = 0);

    // This starts off an asynchronous read.  Upto <bytes_to_read> will
    // be read and stored in the <message_block> or occur error.
    int read (MessageBlock *message_block,
	    size_t bytes_to_read);

    // Destructor.
    virtual ~EpollAsynchReadStream ();
protected:
    // Check the documentation for AsynchOpt::cancel.
    virtual int cancel (void);

    // Read stream and build result.
    virtual int execute (EpollAsynchResult *&);
};
/**
 * @class EpollAsynchReadStreamResult
 *
 * @brief .
 */
class EpollAsynchReadStreamResult : 
    public virtual AsynchReadStreamResultImpl, 
    public EpollAsynchResult
{
    // Factory classes will have special privilages.
    friend class EpollAsynchReadStream;

    // The Proactor constructs the Result class for faking results.
    friend class EpollProactor;
public:
    // The number of bytes which were requested at the start of the
    // asynchronous read.
    virtual size_t bytes_to_read (void) const;
    virtual void bytes_to_read (size_t bytes);

    // Message block which contains the read data.
    virtual MessageBlock *message_block (void) const;
    virtual void message_block (MessageBlock *);

    virtual NDK_HANDLE handle (void) const;

    virtual NDK_HANDLE event (void) const;

    // Destructor.
    virtual ~EpollAsynchReadStreamResult ();
protected:
    // Constructor.
    EpollAsynchReadStreamResult (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    MessageBlock *message_block,
	    size_t bytes_to_read);

    // Proactor will call this method when the read completes.
    //virtual int complete (void);
    virtual int complete (size_t bytes_transferred,
	    int success,
	    const void *completion_key,
	    int error);

    //
    size_t bytes_to_read_;

    //
    size_t bytes_to_read_back_;

    // Message block that contains the data to be read.
    MessageBlock *message_block_;
};
// ---------------------------------------------------------------------
/**
 * @class EpollAsynchWriteStream
 *
 * @brief .
 */
class EpollAsynchWriteStreamResult;
class EpollAsynchWriteStream : 
    public virtual AsynchWriteStreamImpl, 
    public EpollAsynchOpt
{
    // The Proactor constructs the Result class for faking results.
    friend class EpollProactor;
public:
    // Constructor.
    EpollAsynchWriteStream (EpollProactor *p);

    /**
     * Initializes the factory with information which will be used with
     * each asynchronous call.  If (handle == NDK_INVALID_HANDLE),
     * @c AsynchHandler::handle will be called on the handler to get the
     * correct handle. No need for the Proactor since the sub classes
     * will know the correct implementation Proactor class, since this
     * Operation class itself was created by the correct implementation
     * Proactor class.
     */
    virtual int open (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    const void *completion_key,
	    Proactor *proactor = 0);

    // This starts off an asynchronous write.  Upto <bytes_to_write> will
    // be write and stored in the <message_block> or occur error.
    int write (MessageBlock *message_block,
	    size_t bytes_to_write);

    // Destructor.
    virtual ~EpollAsynchWriteStream ();
protected:
    // Check the documentation for AsynchOpt::cancel.
    virtual int cancel (void);

    // Write stream and build result.
    virtual int execute (EpollAsynchResult *&);
};
/**
 * @class EpollAsynchWriteStreamResult
 *
 * @brief .
 */
class EpollAsynchWriteStreamResult : 
    public virtual AsynchWriteStreamResultImpl, 
    public EpollAsynchResult
{
    // Factory classes will have special privilages.
    friend class EpollAsynchWriteStream;

    // The Proactor constructs the Result class for faking results.
    friend class EpollProactor;
public:
    // The number of bytes which were requested at the start of the
    // asynchronous write.
    virtual size_t bytes_to_write (void) const;
    virtual void bytes_to_write (size_t bytes);

    // Message block which contains the write data.
    virtual MessageBlock *message_block (void) const;
    virtual void message_block (MessageBlock *);

    virtual NDK_HANDLE handle (void) const;

    virtual NDK_HANDLE event (void) const;

    // Destructor.
    virtual ~EpollAsynchWriteStreamResult ();
protected:
    // Constructor.
    EpollAsynchWriteStreamResult (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    MessageBlock *message_block,
	    size_t bytes_to_write);

    // Proactor will call this method when the write completes.
    //virtual int complete (void);
    virtual int complete (size_t bytes_transferred,
	    int success,
	    const void *completion_key,
	    int error);

    size_t bytes_to_write_;

    size_t bytes_to_write_back_;

    // Message block that contains the data to be written.
    MessageBlock *message_block_;
};
// ---------------------------------------------------------------------
/**
 * @class EpollAsynchAccept
 *
 * @brief .
 */
class EpollAsynchAcceptResult; 
class EpollAsynchAccept : 
    public virtual AsynchAcceptImpl, 
    public EpollAsynchOpt
{
    // The Proactor constructs the Result class for faking results.
    friend class EpollProactor;
public:
    // Constructor.
    EpollAsynchAccept (EpollProactor *p);

    /**
     * Initializes the factory with information which will be used with
     * each asynchronous call.  If (handle == NDK_INVALID_HANDLE),
     * @c AsynchHandler::handle will be called on the handler to get the
     * correct handle. No need for the Proactor since the sub classes
     * will know the correct implementation Proactor class, since this
     * Operation class itself was created by the correct implementation
     * Proactor class.
     */
    virtual int open (const AsynchHandler *handler,
	    NDK_HANDLE handle,
	    const void *completion_key,
	    Proactor *proactor = 0);

    /**
     * This starts off an asynchronous read. Upto <num_to_accept> of 
     * connections will be accepted and stored in the ConnectionInfo 
     * that be stored in the <message_block> or occur error.  So the 
     * space of the message_block is must equal or large than 
     * <num_to_accept> times size of ConnectionInfo.
     */
    int accept (MessageBlock *message_block,
	    size_t num_to_accept);

    // Destructor.
    virtual ~EpollAsynchAccept ();
protected:
    // Check the documentation for AsynchOpt::cancel.
    virtual int cancel (void);

    // Accept connection and build result.
    virtual int execute (EpollAsynchResult *&);
};
/**
 * @class EpollAsynchAcceptResult
 *
 * @brief .
 */
class EpollAsynchAcceptResult : 
    public virtual AsynchAcceptResultImpl, 
    public EpollAsynchResult
{
    // Factory classes will have special privilages.
    friend class EpollAsynchAccept;

    // The Proactor constructs the Result class for faking results.
    friend class EpollProactor;
public:
    // The number of connection which were requested at the start of the
    // asynchronous accept.
    virtual size_t num_to_accept (void) const; 
    virtual void num_to_accept (size_t num); 

    // Message block which contains the read data.
    virtual MessageBlock *message_block (void) const;
    virtual void message_block (MessageBlock *);

    // I/O handle used for accepting new connections.
    virtual NDK_HANDLE listen_handle (void) const;

    virtual NDK_HANDLE event (void) const;

    //	I/O handle for new connection.
    // virtual NDK_HANDLE accept_handle (void) const;  !!!

    // Destructor.
    virtual ~EpollAsynchAcceptResult ();
protected:
    // Constructor.
    EpollAsynchAcceptResult (const AsynchHandler *handler,
	    NDK_HANDLE listen_handle,
	    MessageBlock *message_block,
	    size_t num_to_accept); 

    // Proactor will call this method when the read completes.
    //virtual int complete (void);
    virtual int complete (size_t bytes_transferred,
	    int success,
	    const void *completion_key,
	    int error);

    NDK_HANDLE listen_handle_;

    size_t num_to_accept_;

    // Message block that contains the data to be written.
    MessageBlock *message_block_;
};

#include "EpollAsynchIO.inl"
#include "Post.h"
#endif

